<?php

declare(strict_types=1);
/**
 * This file is part of MoChat.
 * @link     https://mo.chat
 * @document https://mochat.wiki
 * @contact  group@mo.chat
 * @license  https://github.com/mochat-cloud/mochat/blob/master/LICENSE
 */
namespace MoChat\App\Corp\Action\Dashboard;

use Hyperf\Contract\ConfigInterface;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\HttpServer\Annotation\Middlewares;
use Hyperf\HttpServer\Annotation\RequestMapping;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Codec\Json;
use MoChat\App\Common\Middleware\DashboardAuthMiddleware;
use MoChat\App\Corp\Contract\CorpContract;
use MoChat\App\Corp\Event\CreateCorpEvent;
use MoChat\App\Rbac\Middleware\PermissionMiddleware;
use MoChat\App\Tenant\Contract\TenantContract;
use MoChat\App\WorkMessage\Contract\WorkMessageConfigContract;
use MoChat\Framework\Action\AbstractAction;
use MoChat\Framework\Constants\ErrorCode;
use MoChat\Framework\Exception\CommonException;
use MoChat\Framework\Request\ValidateSceneTrait;
use Psr\EventDispatcher\EventDispatcherInterface;

/**
 * 企业微信授权- 创建提交.
 *
 * Class Store.
 * @Controller
 */
class Store extends AbstractAction
{
    use ValidateSceneTrait;

    /**
     * @Inject
     * @var CorpContract
     */
    protected $corpService;

    /**
     * @Inject
     * @var TenantContract
     */
    protected $tenantService;

    /**
     * @Inject
     * @var WorkMessageConfigContract
     */
    protected $workMessageConfigService;

    /**
     * @Inject
     * @var ConfigInterface
     */
    protected $config;

    /**
     * @Inject
     * @var StdoutLoggerInterface
     */
    private $logger;

    /**
     * @Inject
     * @var EventDispatcherInterface
     */
    private $eventDispatcher;

    /**
     * @RequestMapping(path="/dashboard/corp/store", methods="post")
     * @Middlewares({
     *     @Middleware(DashboardAuthMiddleware::class),
     *     @Middleware(PermissionMiddleware::class)
     * })
     * @return array 返回数组
     * @throws \Exception 异常处理
     */
    public function handle(): array
    {
        // 接收参数
        $params = [
            'name' => trim($this->request->input('corpName')),
            'wx_corpid' => trim($this->request->input('wxCorpId')),
        ];

        if ($this->request->has('appId')) {
            $params['app_id'] = trim($this->request->input('appId'));
        }

        if ($this->request->has('appSecret')) {
            $params['app_secret'] = trim($this->request->input('appSecret'));
        }

        if ($this->request->has('authType')) {
            $params['auth_type'] = (int) $this->request->input('authType');
        }

        // 参数验证
        $this->validated($this->request->all(), 'store');
        $params['created_at'] = date('Y-m-d H:i:s');
        $params['tenantId'] = user()['tenantId'];
        // 判断最大企业数是否超限
        $tenant = $this->tenantService->getTenantByIdWithTrashed($params['tenantId'], ['max_corp']);
        $corps = $this->corpService->getCorpsByTenantId($params['tenantId'], ['id']);
        if (count($corps) >= $tenant['maxCorp']) {
            throw new CommonException(ErrorCode::INVALID_PARAMS, "您最多可添加 {$tenant['maxCorp']} 个企业授权，如需更多，请联系客服！");
        }

        $corp = $this->corpService->getCorpByWxCorpId($params['wx_corpid'], ['id']);
        if (! empty($corp)) {
            throw new CommonException(ErrorCode::INVALID_PARAMS, '您添加的企业ID已存在，请不要重复添加。如需修改请点击配置管理进行修改！');
        }

        // 数据操作
        Db::beginTransaction();
        try {
            // 企业授信
            $corpId = $this->corpService->createCorp($params);
            // 会话存档-配置
            $workMessageConfig = ['corp_id' => $corpId, 'chat_apply_status' => 3, 'created_at' => date('Y-m-d H:i:s')];
            $rsaPrivateKey['version'] = '';
            [$rsaPrivateKey['privateKey'], $rsaPrivateKey['publicKey']] = rsa_keys();
            $chatRsaKey[] = $rsaPrivateKey;
            $workMessageConfig['chat_rsa_key'] = Json::encode($chatRsaKey);
            $this->workMessageConfigService->createWorkMessageConfig($workMessageConfig);
            // 绑定用户与企业的关系
            $container = ApplicationContext::getContainer();
            $redis = $container->get(\Hyperf\Redis\Redis::class);
            $redis->set('mc:user.' . user()['id'], $corpId . '-0');

            Db::commit();
            $this->triggerCreateCorpEvent($corpId);
        } catch (\Throwable $e) {
            Db::rollBack();
            $this->logger->error(sprintf('%s [%s] %s', '企业微信授信创建失败', date('Y-m-d H:i:s'), $e->getMessage()));
            $this->logger->error($e->getTraceAsString());
            throw new CommonException(ErrorCode::SERVER_ERROR, '企业微信授信创建失败');
        }

        return [$corpId];
    }

    /**
     * 触发创建企业事件.
     */
    private function triggerCreateCorpEvent(int $corpId)
    {
        try {
            go(function () use ($corpId) {
                $this->eventDispatcher->dispatch(new CreateCorpEvent([
                    'corpId' => $corpId,
                ]));
            });
        } catch (\Throwable $e) {
            $this->logger->error(sprintf('创建企业事件调度失败，错误信息：%s', $e->getMessage()));
            $this->logger->error($e->getTraceAsString());
        }
    }
}
